package dk.dashboardFP.panels.displayPanel.core {
	import dk.dashboardFP.dfpLogger.DFPLogger;
	import dk.dashboardFP.panels.displayPanel.DisplayEditorControl;
	import dk.dashboardFP.panels.displayPanel.DisplayEditorControlEvent;
	import dk.dashboardFP.panels.displayPanel.DisplayEditorModes;
	import dk.dashboardFP.panels.displayPanel.DisplayPanel;
	import dk.dashboardFP.panels.displayPanel.DragControllerEvent;
	import dk.dashboardFP.utils.keyListener.KeyListener;

	import flash.display.DisplayObject;
	import flash.events.EventDispatcher;
	import flash.events.KeyboardEvent;
	import flash.geom.Point;
	import flash.utils.Dictionary;

	/**
	 * @author josef
	 */
	public class DisplayEditorCore extends EventDispatcher {
		private var _a_oEditorItems : Array;
		private var _a_oSelectionEIs : Array;
		private var _oDisplayeditorControl : DisplayEditorControl;
		private var _bInMoveMode : Boolean = false;
		private var _oDisplayPanel : DisplayPanel;
		private var _pCurrentDrag : Point;
		private var _oDraggingDict : Dictionary;
		private var _bSelectionMarkIsVisible : Boolean = true;

		public function DisplayEditorCore(oDisplayPanel : DisplayPanel) {
			_oDisplayPanel = oDisplayPanel;
			super();
			setupElements();
		}

		private function setupElements() : void {
			
			//:::::::
			// containers
			_a_oEditorItems = [];
			_a_oSelectionEIs = [];
		}

		//::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
		// register controller
		//:::::::::::::::::::::::::::::::::::::::::::::::::::::::::: 

		public function registerController(oDisplayeditorControl : DisplayEditorControl) : void {
			_oDisplayeditorControl = oDisplayeditorControl;
			_oDisplayeditorControl.addEventListener(DisplayEditorControlEvent.CHANGED_MODE, onControlModeChange, false, 0, true);
		}

		private function onControlModeChange(event : DisplayEditorControlEvent) : void {
			if (_oDisplayeditorControl.sCurrentDisplayEditorMode == DisplayEditorModes.MOVE) {
				enterMoveMode();
			} else if (_bInMoveMode) {
				exitMoveMode();
			}
		}

		//::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
		// move mode
		//::::::::::::::::::::::::::::::::::::::::::::::::::::::::::

		private function enterMoveMode() : void {
			_bInMoveMode = true;
			
			_oDisplayPanel.oDragController.addEventListener(DragControllerEvent.START_DRAG, onStartDrag);
			_oDisplayPanel.oDragController.addEventListener(DragControllerEvent.END_DRAG, onEndDrag);
			
			// register keys 
			KeyListener.getInstance().addKeyDown(37, onArrowKey, false);
			KeyListener.getInstance().addKeyDown(39, onArrowKey, false);
			KeyListener.getInstance().addKeyDown(38, onArrowKey, false);
			KeyListener.getInstance().addKeyDown(40, onArrowKey, false);
		}

		private function exitMoveMode() : void {
			_bInMoveMode = false;
		
			_oDisplayPanel.oDragController.removeEventListener(DragControllerEvent.START_DRAG, onStartDrag);
			_oDisplayPanel.oDragController.removeEventListener(DragControllerEvent.END_DRAG, onEndDrag);
			
			// unregister keys 
			KeyListener.getInstance().removeKeyDown(37, onArrowKey);
			KeyListener.getInstance().removeKeyDown(39, onArrowKey);
			KeyListener.getInstance().removeKeyDown(38, onArrowKey);
			KeyListener.getInstance().removeKeyDown(40, onArrowKey);
		}

		//::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
		// key motion
		//::::::::::::::::::::::::::::::::::::::::::::::::::::::::::

		private function onArrowKey() : void {
			var event : KeyboardEvent = KeyListener.getInstance().currentEvent;
			switch(KeyListener.getInstance().currentEvent.keyCode) {
				case 37:
					stepHorizontal(-1, event.shiftKey);
					break;
				case 39:
					stepHorizontal(1, event.shiftKey);
					break;
				case 38:
					stepVertical(-1, event.shiftKey);
					break;
				case 40:
					stepVertical(1, event.shiftKey);
					break;
			}
		}

		private function stepVertical(stepDirection : Number, bigStep : Boolean) : void {
			for each (var item : EditorItem in _a_oSelectionEIs) {
				item.doTarget.y += stepDirection * (bigStep ? 10 : 1);
			}
		}

		private function stepHorizontal(stepDirection : Number, bigStep : Boolean) : void {
			for each (var item : EditorItem in _a_oSelectionEIs) {
				item.doTarget.x += stepDirection * (bigStep ? 10 : 1);
			}
		}		

		//::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
		// drag handlers
		//::::::::::::::::::::::::::::::::::::::::::::::::::::::::::

		private function onEndDrag(event : DragControllerEvent) : void {
			_oDisplayPanel.oDragController.removeEventListener(DragControllerEvent.UPDATE_DRAG, onDragUpdate);
		}

		private function onStartDrag(event : DragControllerEvent) : void {
			_oDisplayPanel.oDragController.addEventListener(DragControllerEvent.UPDATE_DRAG, onDragUpdate);
			_pCurrentDrag = _oDisplayPanel.oDragController.pCurrentDrag;
			
			_oDraggingDict = new Dictionary();
			
			for each (var oEI : EditorItem in _a_oSelectionEIs) {
				_oDraggingDict[oEI] = new Point(oEI.doTarget.x, oEI.doTarget.y);
			}
		}

		private function onDragUpdate(event : DragControllerEvent) : void {
			
			for each (var oEI : EditorItem in _a_oSelectionEIs) {
				
				var pOriginalPos : Point = _oDraggingDict[oEI] as Point;
				
				oEI.doTarget.x = pOriginalPos.x + _pCurrentDrag.x;
				oEI.doTarget.y = pOriginalPos.y + _pCurrentDrag.y;
			}
		}

		//::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
		// add remove selection
		//::::::::::::::::::::::::::::::::::::::::::::::::::::::::::

		public function select(doTarget : DisplayObject, bAddToCurrentSelection : Boolean) : void {
			
			//:::::::
			// if object null 
			if (!doTarget) {
				deselectAll();
				return;
			}
			
			//:::::::
			// get item object 
			var oEI : EditorItem = get_oEIFromTargetDO(doTarget);
			
			//:::::::
			// if add to current
			if (bAddToCurrentSelection) {
				
				//:::::::
				// check if selection add is child of same parent 
				for each (var oEISelected : EditorItem in _a_oSelectionEIs) {
					if (oEISelected.doTarget.parent != doTarget.parent) {
						replaceSelection(oEI);
						return;
					}
				}
				addToSelection(oEI);
			} else {
				replaceSelection(oEI);
			}
		}

		public function deSelect(doTarget : DisplayObject) : void {
			deselectItem(get_oEIFromTargetDO(doTarget));
		}

		//::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
		// toggle selection mark visible
		//::::::::::::::::::::::::::::::::::::::::::::::::::::::::::

		public function toggleSelectionMarkVisible() : void {
			if (_bSelectionMarkIsVisible) {
				hideSelectionMark();
			} else {
				showSelectionMark();
			}
		}

		private function showSelectionMark() : void {
			_bSelectionMarkIsVisible = true;
			for each (var oEI : EditorItem in _a_oSelectionEIs) {
				oEI.doSelectionMark.show();
			}
		}

		private function hideSelectionMark() : void {
			_bSelectionMarkIsVisible = false;
			for each (var oEI : EditorItem in _a_oSelectionEIs) {
				oEI.doSelectionMark.hide();
			}
		}

		//:::::::
		// private 

		private function replaceSelection(oEI : EditorItem) : void {
			deselectAll();
			addToSelection(oEI);
		}

		private function addToSelection(oEI : EditorItem) : void {
			
			//:::::::
			// check if hidden 
			if (!_bSelectionMarkIsVisible) {
				showSelectionMark();
			}

			if (_a_oSelectionEIs.indexOf(oEI)==-1) {
				_a_oSelectionEIs.push(oEI);
				dispatchEvent(new DisplayEditorCoreEvent(DisplayEditorCoreEvent.ITEM_SELCETED, oEI));
			}
			
			dispatchEvent(new DisplayEditorCoreEvent(DisplayEditorCoreEvent.CHANGE_SELECTION, _a_oSelectionEIs[0]));
		}

		public function deselectAll() : void {
			
			while(_a_oSelectionEIs.length != 0) {
				deselectItem(EditorItem(_a_oSelectionEIs[0]), false);
			}
			
			dispatchEvent(new DisplayEditorCoreEvent(DisplayEditorCoreEvent.CHANGE_SELECTION, _a_oSelectionEIs[0]));
		}

		private function deselectItem(oEI : EditorItem, dispathChangeEvent:Boolean=true) : void {
			_a_oSelectionEIs.splice(_a_oSelectionEIs.indexOf(oEI), 1);
			dispatchEvent(new DisplayEditorCoreEvent(DisplayEditorCoreEvent.ITEM_DESELCETED, oEI));
	
			if (dispathChangeEvent) {
				dispatchEvent(new DisplayEditorCoreEvent(DisplayEditorCoreEvent.CHANGE_SELECTION, _a_oSelectionEIs[0]));
			}
		}

		//::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
		// helpers
		//::::::::::::::::::::::::::::::::::::::::::::::::::::::::::

		private function get_oEIFromTargetDO(doTarget : DisplayObject) : EditorItem {
			for each (var oIE : EditorItem in _a_oEditorItems) {
				if (oIE.doTarget == doTarget) {
					return oIE;
				}
			}
			
			var item:EditorItem=new EditorItem(doTarget);
			_a_oEditorItems[_a_oEditorItems.length] = item;
			return item;
		}
		
		public function get hasSingleSelection() : Boolean { 
			return _a_oSelectionEIs.length==1; 
		}
	}
}
